#include "stdafx.h"

#include "video/gbuffer.h"

#include "core/logger.h"

#include "util/check_glerror.h"
#include "util/check_framebuffer.h"

namespace natrium {
	namespace video {
		GBuffer::GBuffer(size_t width, size_t height) {
			gLog.info() << "Creating GBuffer";

			//allocate and configure position buffer (4 channel, 16 bit floats for each channel) [note -- isn't 3 channels enough?]
			glGenTextures(1, &mPositionBuffer);
			glBindTexture(GL_TEXTURE_2D, mPositionBuffer);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

			//allocate and configure normal buffer (3 channel, 16 bit floats per channel)
			glGenTextures(1, &mNormalBuffer);
			glBindTexture(GL_TEXTURE_2D, mNormalBuffer);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, nullptr);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

			//allocate and configure depth buffer (single channel, 32 bit float)
			glGenTextures(1, &mDepthBuffer);
			glBindTexture(GL_TEXTURE_2D, mDepthBuffer);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

			//now, the framebuffer object
			glGenFramebuffers(1, &mHandle);
			glBindFramebuffer(GL_FRAMEBUFFER, mHandle);
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mPositionBuffer, 0);
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mNormalBuffer, 0);
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, mDepthBuffer, 0);

			const GLenum buffers[2] = {
				GL_COLOR_ATTACHMENT0,
				GL_COLOR_ATTACHMENT1
			};

			glDrawBuffers(2, buffers); //configure this framebuffer to use color attachments 0 and 1

			util::CheckFramebuffer();

			//reset to the default framebuffer
			glBindFramebuffer(GL_FRAMEBUFFER, 0);

			util::CheckGLError();
		}

		GBuffer::~GBuffer() {
		}

		GLuint GBuffer::getHandle() const {
			return mHandle;
		}

		GLuint GBuffer::getPositionTexture() const {
			return mPositionBuffer;
		}

		GLuint GBuffer::getNormalTexture() const {
			return mNormalBuffer;
		}

		GLuint GBuffer::getDepthTexture() const {
			return mDepthBuffer;
		}
	}
}